using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Backoffice.Application.Common.Interfaces;
using Backoffice.Application.DTOs;
using Backoffice.Domain.Entities.App;
using Backoffice.Domain.Repositories;
using BackOffice.Application.DTOs;
using BackOffice.Application.Dtos;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using BackOffice.Application.Services;
using Microsoft.AspNetCore.Http;
using BackOffice.Application.Common;

namespace Backoffice.Application.Services;

public class AuthService
{
    private readonly IRepository<AppUser> _repo;
    private readonly IPasswordHasher _hasher;
    private readonly IMemoryCache _cache;
    private readonly IConfiguration _cfg;
    private readonly ILogService _logService;

    public AuthService(IRepository<AppUser> repo, IPasswordHasher hasher, IMemoryCache cache, IConfiguration cfg, ILogService logService)
    {
        _repo = repo; _hasher = hasher; _cache = cache; _cfg = cfg; _logService = logService;
    }
    //注册
    public async Task<AuthResponseDto?> LoginAsync(LoginDto dto)
    {
        return await LoginAsync(dto, null);
    }

    public async Task<AuthResponseDto?> LoginAsync(LoginDto dto, HttpContext? httpContext)
    {

        if (string.IsNullOrWhiteSpace(dto.Username) ||
             string.IsNullOrWhiteSpace(dto.Password))
             throw new Exception("用户名和密码不能为空");

        var key = $"login_fail_{dto.Username}";
        if (_cache.TryGetValue<int>(key, out var fails) && fails >= 5)
            throw new Exception("账户已锁定 30 分钟");

        var user = (await _repo.GetAllAsync()).FirstOrDefault(u => u.Username == dto.Username);
        if (user == null ||!_hasher.VerifyHashedPassword(user.PasswordHash, dto.Password))
        {
            _cache.Set(key, fails + 1, TimeSpan.FromMinutes(30));
            return null;   // 让控制器统一返回 401
        }

        _cache.Remove(key); // 登录成功清除失败计数

        // 记录登录日志
        try
        {
            string clientIp = "127.0.0.1";
            string userAgent = "Unknown";

            if (httpContext != null)
            {
                clientIp = ClientInfoHelper.GetClientIpAddress(httpContext);
                userAgent = ClientInfoHelper.GetUserAgent(httpContext);
            }

            await _logService.RecordLogAsync(new LogRecordDto(
                user.Username,
                "用户登录",
                $"用户 {user.Username} 成功登录系统",
                clientIp,
                userAgent
            ));
        }
        catch (Exception ex)
        {
            // 日志记录失败不影响登录流程
            Console.WriteLine($"记录登录日志失败: {ex.Message}");
        }

        var token = GenerateJwt(user, dto.RememberMe);
        return new AuthResponseDto(user.Id, user.Username, token);
    }

     private string GenerateJwt(AppUser user, bool rememberMe)
    {
        var key = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_cfg["Jwt:Key"]!));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Username)
        };

        var expires = rememberMe
            ? DateTime.UtcNow.AddDays(7)
            : DateTime.UtcNow.AddHours(2);

        var token = new JwtSecurityToken(
            issuer: _cfg["Jwt:Issuer"],
            audience: _cfg["Jwt:Audience"],
            claims: claims,
            expires: expires,
            signingCredentials: creds);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }


    
    //登录
    // public async Task<AppUser?> LoginAsync(string userName, string PasswordHash)
    // {
    //     // var users = await _authRepository.GetAllAsync();
    //     // var user = users.FirstOrDefault(u => u.Username == userName);
    //     // if (user == null)
    //     //     return null;

    //     //  var isValid = _passwordHasher.VerifyHashedPassword(user.PasswordHash,PasswordHash);
    //     //  return isValid ? user : null;   
    // }
     public async Task<AuthResponseDto> RegisterAsync(RegisterDto dto)
    
    {


        if (await _repo.GetAllAsync().ContinueWith(t =>
                t.Result.Any(u => u.Username == dto.Username)))
            throw new Exception("用户名已存在");
         if (dto.Password != dto.ConfirmPassword)
            throw new Exception("密码和确认密码不一致");    

        var hash = _hasher.HashPassword(dto.Password);
        var user = new AppUser(dto.Username, hash, dto.Email,dto.Phone);
        await _repo.CreateAsync(user);

        var token = GenerateJwt(user, rememberMe: false);
        return new AuthResponseDto(user.Id, user.Username, token);


        
    }
    public bool ValidateToken(string token)
    {
        if (string.IsNullOrEmpty(token))
            throw new Exception("Token为空");

        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_cfg["Jwt:Key"]?? throw new Exception("JWT密钥未配置"));

        try
        {
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            }, out SecurityToken validatedToken);

            return true;
        }
        catch
        {
            return false;
        }
    }


    public async Task<List<AuthTreeDto>> GetAuthTreeAsync()
{
    var users = await _repo.GetAllAsync();
    var authTree = BuildAuthTree(users, null);
    return authTree;
}

private List<AuthTreeDto> BuildAuthTree(IEnumerable<AppUser> users, Guid? Id)
{
    var authTree = users
        .Where(u => u.Id == Id)
        .Select(u => new AuthTreeDto
        {
            Id = u.Id,
            Username = u.Username,
            Email = u.Email,
            Phone = u.Phone,
            Children = BuildAuthTree(users, u.Id)
        })
        .ToList();

    return authTree;
}

    // 发送验证码
    public async Task<object> SendVerificationCodeAsync(SendVerificationCodeDto dto)
    {
        if (string.IsNullOrWhiteSpace(dto.Username) || string.IsNullOrWhiteSpace(dto.Phone))
            throw new Exception("用户名和手机号不能为空");

        var users = await _repo.GetAllAsync();
        var user = users.FirstOrDefault(u => u.Username == dto.Username && u.Phone == dto.Phone);
        
        if (user == null)
            throw new Exception("用户名或手机号不正确");

        // 生成6位验证码
        var verificationCode = new Random().Next(100000, 999999).ToString();
        
        // 将验证码存储到缓存中，5分钟有效期
        var cacheKey = $"verification_code_{dto.Username}_{dto.Phone}";
        _cache.Set(cacheKey, verificationCode, TimeSpan.FromMinutes(5));

        // 这里应该调用短信服务发送验证码
        // 目前只是模拟发送
        return new { Message = "验证码已发送", Code = verificationCode };
    }

    // 重置密码
    public async Task<object> ResetPasswordAsync(ResetPasswordDto dto)
    {
        if (string.IsNullOrWhiteSpace(dto.Username) || 
            string.IsNullOrWhiteSpace(dto.Phone) || 
            string.IsNullOrWhiteSpace(dto.VerificationCode) || 
            string.IsNullOrWhiteSpace(dto.NewPassword))
            throw new Exception("所有字段都不能为空");

        // 验证验证码
        var cacheKey = $"verification_code_{dto.Username}_{dto.Phone}";
        if (!_cache.TryGetValue<string>(cacheKey, out var storedCode) || storedCode != dto.VerificationCode)
            throw new Exception("验证码不正确或已过期");

        var users = await _repo.GetAllAsync();
        var user = users.FirstOrDefault(u => u.Username == dto.Username && u.Phone == dto.Phone);
        
        if (user == null)
            throw new Exception("用户名或手机号不正确");

        // 更新密码
        var newPasswordHash = _hasher.HashPassword(dto.NewPassword);
        user.ChangePassword(newPasswordHash);
        await _repo.UpdateAsync(user);

        // 清除验证码缓存
        _cache.Remove(cacheKey);

        return new { Message = "密码重置成功" };
    }

    /// <summary>
    /// 修复数据库中的密码哈希问题
    /// </summary>
    public async Task<bool> FixPasswordHashesAsync()
    {
        try
        {
            var users = await _repo.GetAllAsync();
            var fixedCount = 0;

            foreach (var user in users)
            {
                // 检查是否是旧的明文密码哈希
                if (user.PasswordHash == "113" || !user.PasswordHash.StartsWith("$2a$"))
                {
                    // 为admin用户设置默认密码"password"
                    string newPassword = user.Username == "admin" ? "password" : "123456";
                    string newHash = _hasher.HashPassword(newPassword);
                    
                    user.ChangePassword(newHash);
                    await _repo.UpdateAsync(user);
                    fixedCount++;
                }
            }

            return fixedCount > 0;
        }
        catch (Exception ex)
        {
            // 记录错误但不抛出异常
            Console.WriteLine($"修复密码哈希时出错: {ex.Message}");
            return false;
        }
    }
}